//
//  NotiManager.swift
//  ZJTools
//
//  Created by 万孟超 on 2023/12/6.
//

import Foundation

fileprivate struct NotiManagerModel {
    
    struct NotiDetailModel {
        
        typealias NotiCallBack = (NSNotification.Name, [AnyHashable: Any]?) -> ()
        
        var target: AnyObject
        
        var callBack: NotiCallBack
    }
    
    var notiMap: [NSNotification.Name: [NotiDetailModel]] = [:]
    
}

fileprivate class NotiInfoShare {
    static let shared = NotiInfoShare()
    
    private init() { }
    
    var model = NotiManagerModel()
    
    @objc func notificationCallBack(_ notification: Notification) {
        if let notiDetailArray = NotiInfoShare.shared.model.notiMap[notification.name] {
            for notiModel in notiDetailArray {
                notiModel.callBack(notification.name, notification.userInfo)
            }
        }
    }
    
    private let center = NotificationCenter.default
    
        
    func post(_ name: NSNotification.Name, userInfo: [AnyHashable : Any]? = nil) {
        postNotification(name, userInfo: userInfo)
    }
    
    func add(_ observer: AnyObject, name: NSNotification.Name, selector: Selector) {
        center.addObserver(observer, selector: selector, name: name, object: nil)
    }
    
    func add(_ observer: AnyObject, name: NSNotification.Name, block: @escaping NotiManagerModel.NotiDetailModel.NotiCallBack) {
        center.addObserver(self, selector: #selector(notificationCallBack(_:)), name: name, object: nil)
        var notiDetail = model.notiMap[name] ?? []
        let currentDetailModel = NotiManagerModel.NotiDetailModel(target: observer, callBack: block)
        notiDetail.append(currentDetailModel)
        model.notiMap[name] = notiDetail
    }
    
    func remove(_ observer: AnyObject, name: NSNotification.Name? = nil) {
        if let name = name {
            model.notiMap[name]?.removeAll(where: {$0.target === observer})
            if let array = model.notiMap[name], array.isEmpty {
                model.notiMap.removeValue(forKey: name)
            }
        }else{
            for notiName in NotiInfoShare.shared.model.notiMap.keys {
                model.notiMap[notiName]?.removeAll(where: {$0.target === observer})
                if let array = model.notiMap[notiName], array.isEmpty {
                    model.notiMap.removeValue(forKey: notiName)
                }
            }
        }
    }
    
    private func postNotification(_ name: NSNotification.Name, userInfo: [AnyHashable : Any]? = nil) {
        center.post(name: name, object: nil, userInfo: userInfo)
    }
}

class NotiManager {
        
    private init() { }
    
    private static let notiShare = NotiInfoShare.shared
        
    @discardableResult
    static func post(_ name: NSNotification.Name, userInfo: [AnyHashable : Any]? = nil) -> NotiManager.Type {
        notiShare.post(name, userInfo: userInfo)
        return self
    }
    
    @discardableResult
    static func add(_ observer: AnyObject, name: NSNotification.Name, selector: Selector) -> NotiManager.Type {
        notiShare.add(observer, name: name, selector: selector)
        return self
    }
    
    @discardableResult
    static func add(_ observer: AnyObject, name: NSNotification.Name, block: @escaping (NSNotification.Name, [AnyHashable: Any]?) -> ()) -> NotiManager.Type {
        notiShare.add(observer, name: name, block: block)
        return self
    }
    
    static func remove(_ observer: AnyObject, name: NSNotification.Name? = nil) {
        notiShare.remove(observer, name: name)
    }
    
}
